package com.tsj.spzx.pay.controller;

import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.tsj.spzx.model.vo.common.Result;
import com.tsj.spzx.model.vo.common.ResultCodeEnum;
import com.tsj.spzx.pay.Properties.AlipayProperties;
import com.tsj.spzx.pay.service.AlipayService;
import com.tsj.spzx.pay.service.PaymentInfoService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.util.Map;

@Tag(name = "支付接口")
@Controller
@RequestMapping("/api/order/alipay")
public class AlipayController {

    @Autowired
    private AlipayService alipayService;
    @Autowired
    private PaymentInfoService paymentInfoService;
    @Autowired
    private AlipayProperties alipayProperties;

    /**
     * 系统令牌解决远程调用丢失token的方法:
     * 好的，在你讲解了以后，我在原有理解上又有了变化，你看看有没有问题：
     * 1、先设置配置类，用于生成系统令牌 systemToken，
     * 2、Feign拦截器，只拦截远程调用的接口，我们可以规定远程调用接口必须全部以/feign开头，然后让feign拦截器只拦截以/feign开头的链接，为他们配置上系统令牌，
     * 3、普通拦截器在拦截时，如果判断到他是以/feign开头的，就验证他携带的系统令牌是否正确，然后选择是否放行，当然还可以拦截其他请求，拦截的其他请求就可以正常判断token，
     * 4、在使用时，我们可以配置AuthContext，在远程调用前先(异步时最好提前设置AuthContext.setToken（systemToken),简单点不想保留AuthContext时，
     * 我们就强制所有远程调用必须以/feign开头),然后增强feign拦截器，让他优先从AuthContext中获取token，如果为不null，就设置token为当前token，
     * 为null，再让他为请求添加token，这样做到双重保险，我们不能保证所有远程调用都以/feign开头，就最好保留AuthContext，
     * 注：异步任务会产生新线程，由于线程隔离，可能会导致上下文丢失，从上下文中获取token就会永远为null。
     */

    /**
     * ** 确认支付 ** 流程
     * 1、我们的程序 去调用 支付宝服务的接口
     *    我们根据订单编号，保存订单信息
     *    调用支付宝服务的接口，返回一个form表单页面，
     * 2、在支付完成后，支付宝会调用我们的两个接口
     *    return_payment_url: http://192.168.10.100/#/pages/money/paySuccess   支付完成后跳转到成功或者失败页面
     *    notify_payment_url: http://127.0.0.1:3013/api/order/alipay/callback/notify
     *      支付成功后 支付宝的回调，进行订单状态的修改，修改订单状态为已支付，修改库存，修改商品销量，。。。。操作
     * 问题：
     *    我们是本地部署，支付宝肯定不能带哦用我们的本地路径
     *    1、使用域名解决
     *    2、使用内网穿透技术（在项目中，我们使用此方法）
     */

    /**
     * ** 确认支付 **
     * 点击确认支付，跳转到支付宝支付页面（调用支付宝的接口 给我们返回一个String类型的form表单页面）
     * @param orderNo
     * @return
     */
    @Operation(summary="支付宝下单")
    @ResponseBody
    @GetMapping("/submitAlipay/{orderNo}")
    public Result<String> submitAlipay(@PathVariable("orderNo") String orderNo) {
        String form = alipayService.submitAlipay(orderNo);
        return Result.build(form, ResultCodeEnum.SUCCESS);
    }

    /**
     * 那么也就是说，我用的是沙箱测试环境，所以支付时也是沙箱的支付，
     * 但在实际开发时，我如果换成了真时商家注册后获得的AppId等信息，
     * 那么我的代码也就是只需要更换以下AppId这些信息，然后就可以真实支付了
     */
    /**
     * 订单支付成功后，支付宝会回调我们的接口，进行订单状态的修改，修改订单状态为已支付，修改库存，修改商品销量，。。。。操作
     * @return
     */
    @Operation(summary="支付成功后 支付宝回调")
    @ResponseBody
    @RequestMapping("/callback/notify")
    public String callbackNotify(@RequestParam Map<String, String> paramMap, HttpServletRequest request ) {
        System.out.println("====================> paramMap: " + paramMap);
        // 1、首先进行 签名验证
        boolean signVerified = false;
        try {
            signVerified = AlipaySignature.rsaCheckV1(paramMap,
                    alipayProperties.getAlipayPublicKey(),
                    AlipayProperties.charset,
                    AlipayProperties.sign_type);
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }

        if (signVerified){
            // 验签成功后，对支付结果进行校验，校验成功后再惊醒更新。。。操作
            // 获取交易状态
            String trade_status = paramMap.get("trade_status");
            if("TRADE_SUCCESS".equals(trade_status) || "TRADE_FINISHED".equals(trade_status)){
                // 交易成功 进行后续更新操作
                paymentInfoService.updatePaymentInfo(paramMap);
                return "success";
            }
        }else {
            return "failure";
        }

        return "failure";
    }
}
